

'''
双色球数据处理
'''

from util.sqlalchemy_util import *;
import numpy as np;
import pandas as pd;
from pandas import Series, DataFrame;
import random;
from pyecharts.faker import Faker;
from pyecharts import options as opts;
from pyecharts.charts import Bar, Bar3D, Line, Line3D, Pie, Map, Geo, Funnel, Grid, Tab, Page;
from statsmodels.tsa.api import SimpleExpSmoothing, Holt;
from util.LSTM_Model import *;

# 获取所有数据，构造 dateframe 对象
def build_dcb_df():
    print("======== 初始化df数据 ========");
    # 从数据库读取数据
    sql = "select issur_code, occur_date, red_ball, blue_ball from double_color_ball order by occur_date";
    result = execute_(sql);
    column_list = ["期号", "开奖日期", "红球", "蓝球"];
    df = DataFrame(data=result, columns=column_list);
    df = pd.concat([
        df[["期号", "开奖日期"]],
        df["红球"].str.split(" ", expand=True).rename(
            columns={0: '红球1', 1: '红球2', 2: '红球3', 3: '红球4', 4: '红球5', 5: '红球6'}),
        df["蓝球"],
    ], axis=1);
    print(df);
    return df;

# 绘制最近30期中奖号码走势图
def draw_dcb_lines(df):
    print("======== 绘制走势图 ========");

    # 准备数据
    occure_date = np.asarray(df["开奖日期"][-30:].apply(lambda item:str(item))).tolist();
    red1 = np.asarray(df["红球1"][-30:].apply(lambda item:int(item))).tolist();
    red2 = np.asarray(df["红球2"][-30:].apply(lambda item:int(item))).tolist();
    red3 = np.asarray(df["红球3"][-30:].apply(lambda item:int(item))).tolist();
    red4 = np.asarray(df["红球4"][-30:].apply(lambda item:int(item))).tolist();
    red5 = np.asarray(df["红球5"][-30:].apply(lambda item:int(item))).tolist();
    red6 = np.asarray(df["红球6"][-30:].apply(lambda item:int(item))).tolist();
    blue = np.asarray(df["蓝球"][-30:].apply(lambda item:int(item))).tolist();

    Line().add_xaxis(
        xaxis_data=occure_date
    ).add_yaxis(
        series_name="红1",
        y_axis=red1,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).add_yaxis(
        series_name="红2",
        y_axis=red2,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).add_yaxis(
        series_name="红3",
        y_axis=red3,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).add_yaxis(
        series_name="红4",
        y_axis=red4,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).add_yaxis(
        series_name="红5",
        y_axis=red5,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).add_yaxis(
        series_name="红6",
        y_axis=red6,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).add_yaxis(
        series_name="蓝球",
        y_axis=blue,
        itemstyle_opts=opts.ItemStyleOpts(color=Faker.rand_color())
    ).set_global_opts(
        title_opts=opts.TitleOpts(title="双色球走势图", subtitle="近30期", pos_left="10%"),
        # 设置 series_name 位置
        legend_opts=opts.LegendOpts(pos_left="40%"),
    ).render(
        path="/temp/dcb.html"
    );

'''
    - 添加号码到号码池
    - l：号码池
    - nimber：号码
    - is_blue：是否为蓝球
'''
def add_number_to_pool(l, number, is_blue):
    max = 16 if is_blue else 33;
    # 蓝球直接添加
    if is_blue:
        l.append(number);
        return l;
    elif (not is_blue) and (not l.__contains__(number)):
        l.append(number);
        l.sort();
        return l;
    else:
        add_number_to_pool(l, random.randint(1, max), is_blue);

# 随机生成双色球
def random_dcb_predict():
    print("======== 随机算法预测 ========");
    l = [];
    for i in range(1, 8):
        is_blue = False if i < 7 else True;
        max = 16 if is_blue else 33;
        add_number_to_pool(l, random.randint(1, max), is_blue);
    print(l);
    return l;

# 平滑曲线预测
def smoothing_dcb_predict(df):
    print("======== 平滑指数预测 ========");
    l = [];
    for i in range(1, 8):
        column = "红球%d" % i if i < 7 else "蓝球";
        is_blue = False if i < 7 else True;

        ses = SimpleExpSmoothing(
            np.asarray(df[column].apply(lambda item:int(item)))
        ).fit(
            smoothing_level=random.randint(1, 10) / 10,
            optimized=False
        );

        # 用适应模型预测数据，返回数组 [3.98919522]
        result = ses.predict();
        munber = int(round(result[0], 0));
        # print(result, munber);
        add_number_to_pool(l, munber, is_blue);

    print(l);
    return l;

# holt 预测
def holt_dcb_predict(df):
    print("======== Holt预测 ========");
    l = [];
    for i in range(1, 8):
        column = "红球%d" % i if i < 7 else "蓝球";
        is_blue = False if i < 7 else True;

        holt = Holt(
            np.asarray(df[column].apply(lambda item: int(item)))
        ).fit(
            smoothing_level=random.randint(1, 10) / 10,
            smoothing_trend = random.randint(1, 10) / 10,
            optimized = False
        );

        # 用适应模型预测数据，返回数组 [3.98919522]
        result = holt.predict();
        munber = int(round(result[0], 0));
        add_number_to_pool(l, munber, is_blue);

    print(l);
    return l;

# lstm 预测
def lstm_dcb_predict(df):
    print("======== LSTM 预测 ========");
    l = [];
    for i in range(1, 8):
        column = "红球%d" % i if i < 7 else "蓝球";
        is_blue = False if i < 7 else True;

        lstm = LSTM_Model(data=np.asarray(df[column].apply(lambda item: int(item))), step_length=3);
        lstm.application();
        munber = int(round(lstm.predict[-1]));
        add_number_to_pool(l, munber, is_blue);

    print(l);
    return l;

def save_predict_data(result=""):
    print("======== 保存预测结果 ========");
    print(result);
    # 查找数据库最近一条数据
    query_sql = "select id from double_color_ball order by occur_date desc limit 1";
    ids = execute_(query_sql);
    id = 0 if len(ids) == 0 else ids[0][0];

    # 修改推荐号
    update_sql = "update double_color_ball set recommend='%s' where id=%s;" % (result, id);
    execute_(update_sql);

# 调度程序
def application():
    result = [];
    df = build_dcb_df();
    draw_dcb_lines(df);
    l = random_dcb_predict();
    result.append("<p>随机预测：%s</p>" % l);
    l = smoothing_dcb_predict(df);
    result.append("<p>平滑指数预测：%s</p>" % l);
    l = holt_dcb_predict(df);
    result.append("<p>Holt 预测：%s</p>" % l);
    l = lstm_dcb_predict(df);
    result.append("<p>LSTM 预测：%s</p>" % l);
    save_predict_data("".join(result));

if __name__ == '__main__':
    # df = build_dcb_df();
    # draw_dcb_lines(df);
    # l = random_dcb_predict();
    # print(l);
    # l = smoothing_dcb_predict(df);
    # print(l);
    # l = holt_dcb_predict(df);
    # print(l);
    # l = lstm_dcb_predict(df);
    # print(l);
    # save_predict_data("aaaaa");
    application();
